package acptTests;

import java.util.Random;


import msgParser.Strings;

import org.junit.Before;
import org.junit.Test;

import reactor.ConnectionHandler;
import tokenizer.StringMessage;

	/*
	 * Functionality Test
	 * Purpose: Test the existence of all the basic functionality
	 * guaranteed in the release.
	 * This test aims to test all the use-cases in a simple form
	 * with valid input and according to the specification.
	 */
public class FunctionalityTest extends ServerTest
{
	protected int UserID;
	protected int adminID;
	protected int ForumID;
	protected int SubForumID;
	protected int TopicID;
	protected int ReplyID;
	
	@Before
	public void setUp()
	{	
		super.setUp();
	}
	
	public StringMessage send(StringMessage str , ConnectionHandler ch)
	{
		return sp.processMessage(str , ch);
	}
	
	@Test
	public void testInit()
	{
		StringMessage m = send(new StringMessage("INIT_FORUM \0 test_uber_admin \0 a4rpcX_"),ch);
		assertNotNull(m);
		assertEquals(m.toString(), "INIT_OK");
	}
	
	@Test
	public void testLogin()
	{
		testInit();
		StringMessage m = send(new StringMessage("ADMIN_LOGIN \0 test_uber_admin \0 a4rpcX_"),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("LOGGED_IN"));
		UserID =  Integer.parseInt(getWord(m.toString(), 1));
	}
	
	@Test
	public void testRegister()
	{
		testAddForum();
		send(new StringMessage("LOGOUT\0"),ch);
		StringMessage m = send(new StringMessage("REGISTER\0testreg\0pass123\0maximdzagoev@gmail.com"+ Math.random() +"\0"+ ForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("REGISTERED"));
		UserID = Integer.parseInt(getWord(m.toString(), 1));
	}
	
	@Test
	public void testAddForum()
	{
		testLogin();
		String Policies = Strings.IMMEDIATE_NOTIFY+"\0" + Strings.FORUM_MEMBERS_NOTIFY +"\0 "+ 1 +"\0" +Strings.AUTHOR_FORUM_DELETE_POST+"\0"
		+Strings.MIN_POST_ADD_MODERATOR+"\0"+Strings.CANNOT_REMOVE_SINGLE_MODERATOR+"\0"+ 
		Strings.VALID_EMAIL_SECURITY+"\0" +Strings.REJECT_BAD_WORDS;
		
		//need to acquire the admin's ManagerID for the next message:
		StringMessage m = send(new StringMessage("ADD_FORUM \0 General Discussion \0 " + UserID +" \0 " + Policies),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("FORUM_ADDED"));
		ForumID = Integer.parseInt(getWord(m.toString(), 1));
	}
	
	@Test
	public void testShowAllForums()
	{
		//testLogin();
		testAddForum();
		//need to acquire the admin's ManagerID for the next message:
		StringMessage m = send(new StringMessage("SHOW_FORUMS"),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_SHOW_FORUMS"));
		assertEquals(Integer.parseInt(getWord(m.toString(), 2)), ForumID);
	}
	
	@Test
	public void testNewSubForum()
	{
		//testLogin();
		testAddForum();
		//need to acquire the Forum ID for the next message:
		StringMessage m = send(new StringMessage("ADD_SUBFORUM \0 Cars \0 " + ForumID + "\0" + UserID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("SUBFORUM_ADDED"));
		SubForumID = Integer.parseInt(getWord(m.toString(), 1));
	}
	
	@Test
	public void testShowForum() //show forum's subforums
	{
		//testLogin();
		//testAddForum();
		//testNewSubForum();
		testNewMessage();
		//need to acquire the Forum ID for the next message:
		StringMessage m = send(new StringMessage("SHOW_SUBFORUMS \0 " + ForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_SHOW_SUBFORUMS"));
		System.out.println(getWord(m.toString(), 2));
	}
	
	@Test
	public void testNewMessage()
	{
		//testLogin();
		//testAddForum();
		testNewSubForum();
		//need to acquire the Sub-Forum ID for the next message:
		StringMessage m = send(new StringMessage("ADD_TOPIC \0 My new car \0 I just got it and bla bla bla... \0 " + SubForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("TOPIC_ADDED"));
		TopicID = Integer.parseInt(getWord(m.toString(), 1));
	}
	
	@Test
	public void testNewReply()
	{
		testNewMessage();
		StringMessage m = send(new StringMessage("ADD_REPLY \0 good one, tell me more! \0 " + TopicID),ch);
		assertNotNull(m);
		
		assertTrue(m.toString().startsWith("REPLY_ADDED"));
		ReplyID = Integer.parseInt(getWord(m.toString(), 1));
	}
	
	@Test 
	public void testLogout()
	{
		testLogin();
		StringMessage m = send(new StringMessage("LOGOUT"),ch);
		assertNotNull(m);
		assertEquals(m.toString(), "LOGGED_OUT");
	}
	
	@Test
	public void testShowAllUsers()
	{
		testLogin();
		StringMessage m = send(new StringMessage("SHOW_SYSTEM_USERS"),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_SHOW_SYSTEM_USERS\0test_uber_admin\0" + UserID));
	}
	
	@Test
	public void testShowSubForum()
	{
		testNewMessage();
		StringMessage m = send(new StringMessage("SHOW_TOPICS \0 " + SubForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_SHOW_TOPICS\0My new car\0" + TopicID));
	}
	
	@Test
	public void testShowPost()
	{
		testNewReply();
		StringMessage m = send(new StringMessage("SHOW_MESSAGES\0" + TopicID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_SHOW_MESSAGES"));
	}
	
	@Test
	public void testRemoveTopic()
	{
		testNewMessage();
		StringMessage m = send(new StringMessage("REMOVE_TOPIC \0 " + TopicID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("TOPIC_REMOVED"));	
	}
	/*
	@Test
	public void testRemoveReply()
	{
		testNewMessage();
		StringMessage m = send(new StringMessage("REMOVE_TOPIC \0 " + TopicID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("TOPIC_REMOVED"));	
	}*/
	
	@Test
	public void testAddSubForumModerator()
	{
		testNewSubForum();
		StringMessage m = send(new StringMessage("ADD_MODERATOR \0 " + UserID + "\0" + SubForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("MODERATOR_ADDED"));	
	}
	
	@Test
	public void testRemoveSubForum()
	{
		testNewSubForum();
		StringMessage m = send(new StringMessage("REMOVE_SUBFORUM \0 " + SubForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("SUBFORUM_REMOVED"));	
	}
	@Test
	public void testRemoveSubForumModerator()
	{
		testAddSubForumModerator();
		StringMessage m = send(new StringMessage("REMOVE_MODERATOR \0 " + UserID + "\0" + SubForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("MODERATOR_REMOVED"));	
	}
	
	@Test
	public void testGetNumberOfMessagesInSubForum()
	{
		testNewSubForum();
		StringMessage m = send(new StringMessage("GET_SUBFORUM_SIZE \0 " + SubForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_GET_SUBFORUM_SIZE"));
		assertEquals(getWord(m.toString(), 1), "0");
	}
	
	@Test
	public void testGetUserMSGCOUNT()
	{
		testNewMessage();
		StringMessage m = send(new StringMessage("GET_USER_MSGCOUNT \0 " + UserID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_GET_USER_MSGCOUNT"));
		assertEquals(getWord(m.toString(), 1), "1");
	}
	
	
	
	@Test
	public void testGetNumberOfForums()
	{
		testAddForum();
		StringMessage m = send(new StringMessage("GET_FORUM_COUNT"),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_GET_FORUM_COUNT"));
		assertEquals(getWord(m.toString(), 1), "1");		
	}
	
	@Test
	public void testGetUsernamesRegisteredToMoreThanOneForum()
	{
		testAddForum();
		String Policies = Strings.IMMEDIATE_NOTIFY+"\0" + Strings.FORUM_MEMBERS_NOTIFY +"\0"+ 1 +"\0" +Strings.AUTHOR_FORUM_DELETE_POST+"\0"
				+Strings.MIN_POST_ADD_MODERATOR+"\0"+Strings.CANNOT_REMOVE_SINGLE_MODERATOR+"\0"+ 
				Strings.VALID_EMAIL_SECURITY+"\0" +Strings.INFORM_MODERATOR_BAD_WORDS;
		send(new StringMessage("ADD_FORUM \0 General Discussion 2\0 " + UserID + Policies),ch);
		send(new StringMessage("LOGOUT"),ch);
		send(new StringMessage("REGISTER \0 user \0 pass \0" + 1),ch);
		send(new StringMessage("LOGOUT"),ch);
		StringMessage m2 = send(new StringMessage("REGISTER \0 user \0 pass \0 maximdzagoev@post.bgu.ac.il\0" + 2),ch);
		send(new StringMessage("LOGOUT"),ch);
		send(new StringMessage("LOG_IN \0 test_uber_admin \0 a4rpcX_"),ch);
		StringMessage m = send(new StringMessage("GET_COMMON_USERS"),ch);
		assertNotNull(m);
		//System.out.println("\n\n\n\n tal tal tal \n\n\n\n"+m.getMessage());
		assertTrue(m.toString().startsWith("ERROR_GET_COMMON_USERS"));		
	}
	
	@Test
	public void testShowUsersOfForum()
	{
		testAddForum();
		send(new StringMessage("LOGOUT"),ch);
		send(new StringMessage("REGISTER \0 user \0 pass \0maximdzagoev@post.bgu.ac.il\0" + ForumID),ch);
		send(new StringMessage("LOGOUT"),ch);
		send(new StringMessage("LOG_IN \0 test_uber_admin \0 a4rpcX_"),ch);
		StringMessage m = send(new StringMessage("SHOW_FORUM_USERS \0" + ForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ANS_SHOW_FORUM_USERS"));
		//System.out.println(m.getMessage());
		assertEquals(getWord(m.toString(), 1), "user");
	}
	
	/********************** Learning algorithm Tests *****************************/

	@Test
	public void testCurses()
	{
		testNewSubForum();
		//need to acquire the Sub-Forum ID for the next message:
		StringMessage m = send(new StringMessage("ADD_TOPIC \0 I got a new car you fuckface! \0 it's so gorgeus! \0 " + SubForumID),ch);
		assertNotNull(m);
		assertTrue(m.toString().startsWith("ERROR_ADD_TOPIC"));
		
		StringMessage m1 = send(new StringMessage("ADD_TOPIC \0 My new car \0 is freaking nuts! \0 " + SubForumID),ch);
		assertNotNull(m1);
		assertTrue(m1.toString().startsWith("TOPIC_ADDED"));
	}
	
	@Test
	public void testLearnability()
	{
		testNewSubForum();
		int trainPoint = 20;
		int Low = 5;				//min word length
		int High = 15;				//max word length
		int numOfWords = 100;		// num of InContext words
		String InContext[] = new String[100];
		Random r = new Random(); // Intialize a Random Number Generator with SysTime as the seed
		 	
		int wordLength = r.nextInt(High-Low) + Low;		//
		
		//fill InContext array with randomly generated strings
		for (int k=0; k<100; k++) 
		{
		    StringBuilder sb = new StringBuilder(wordLength);
		    for(int i = 0; i < wordLength; i++) 	
		    { // For each generated letter in the word
		        char tmp = (char) ('a' + r.nextInt('z' - 'a')); // Generate a letter between a and z
		        sb.append(tmp); // Add it to the String
		    }
		InContext[k] = sb.toString();				//add word to array of InContext strings
		wordLength = r.nextInt(High-Low) + Low;		//wordLength for next word	
		}
		
		//train the classifier on 3 words each time out of InContext
		for (int i=0; i<trainPoint+1; i++)
		{
			int word1 = r.nextInt(numOfWords);
			int word2 = r.nextInt(numOfWords);
			int word3 = r.nextInt(numOfWords);
			
			StringMessage m = send(new StringMessage("ADD_TOPIC \0 " + InContext[word1] + " \0 " + InContext[word2]+" " + InContext[word3] + " \0 " + SubForumID),ch);
			assertNotNull(m);
			assertTrue(m.toString().startsWith("TOPIC_ADDED"));
			TopicID = Integer.parseInt(getWord(m.toString(), 1));
		}
		
		StringMessage m1 = send(new StringMessage("ADD_TOPIC \0 My new car \0 is freaking nuts! \0 " + SubForumID),ch);
		assertNotNull(m1);
		assertTrue(m1.toString().startsWith("ERROR_ADD_TOPIC"));
	}

	
}

